﻿using System;
using System.Linq;
using System.Xml.Linq;
using System.ComponentModel;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using System.Windows.Browser;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using QXGameEngine.Control;
using QXGameEngine.Interface;
using QXGameEngine.Logic;
using QXGame_Silverlight3.AStar;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;
using gameserver;

/*******************************************************************************
 * 
 * 本引擎所有代码均为“覃旋(QX)”编写，网名：“深蓝色右手”，所有权归“覃旋(QX)”
 * 本引擎所有素材资源均来源于网络，请勿将任何素材用作商业用途，否则后果自负
 * 
 * 本引擎当前的目标是实现2D-MMORPG的所有单机功能，并努力使结构与性能最大优化
 * Silverlight在通信方面有着强大的Socket和WCF，需要开发网络游戏的朋友可自行研究
 * 
 * 如打算使用此引擎做商业游戏引擎的朋友，我只有一个小小的请求：在您的游戏主页
 * 最下方注名：基于深蓝游戏引擎(QXGameEngine)开发，并附上我博客的地址，谢谢
 * 
 * 引擎在不断更新，每次更新都凝结着我与我的几个QQ群里所有朋友的帮助与支持
 * 大家都因为共同的梦想走到了一起，Silverlight给了我们一个大展身手的平台，
 * 我一直坚信，未来会更美好！
 * 
 * -------------------------------技术交流QQ群----------------------------------
 * 73068105(1群):深蓝WPF/Silverlight  高手很多,加入时请注明.NET开发经验(限3年以上)
 * 20167206(2群):Silverlight3游戏开发 专业讨论基于Silverlight3.0+的游戏开发技术
 * 92298919(3群):WPF/SL3游戏开发      欢迎广大朋友们加入,专门为新手设立的群
 * 93932965(4群):Silverlight深蓝引擎  主要讨论QXGameEngine的优化、改进与重构
 * ----------------------欢迎大家根据自己的需要加入相应的群---------------------
 * 
 ******************************************************************************/

namespace QXGameEngine {
    public partial class MainPage : UserControl {

        public MainPage() {
            InitializeComponent();
            InitializeGameArguments();
            InitializeGameConfig();
            InitializeGameObject();
            InitializeGameInterface();
          //  InitializeNetWork();
        }
        #region 初始化网络
        private void InitializeNetWork() 
        {
            Globle.client = new AsyncClient(4096);
            Globle.client.Connect("127.0.0.1", 4502);
            Globle.client.DataRecieved += new AsyncConnectionEventHandler(Data_Recive);
            //网络发包接受计时器
            DispatcherTimer gamePacketTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(100) };
            gamePacketTimer.Tick += new EventHandler(gamePacketTimer_Tick);
            gamePacketTimer.Start();
        }
        void Data_Recive(object sender, AsyncConnectionEventArgs e)
        {
            byte[] bytes = (byte[])e.Buff.Clone();
            Globle.PacketList.Enqueue(bytes);

        }
        #endregion

        #region 初始化游戏参数

        /// <summary>
        /// 初始化游戏参数
        /// </summary>
        private void InitializeGameArguments() {
            //加载系统参数
            Super.LoadXElement("Arguments", XElement.Load(@"Config/Setting.xml"));
            //加载魔法附加效果参数
            Super.LoadXElement("AdditionalEffects", Super.GetXElement(Super.Settings["Arguments"], "AdditionalEffects"));
            //加载魔法附加效果颜色
            Super.AdditionalEffectColor = new Color[6] { Colors.White, Colors.Yellow, Color.FromArgb(255, 48, 143, 241), Colors.Green, Colors.Red, Colors.Black };
            //加载升级经验值表到内存
            IEnumerable<XElement> levelList = Super.GetXElement(Super.Settings["Arguments"], "LevelUp").Elements("Experience");
            int listCount = levelList.Count();
            Super.LevelUpExperienceList = new int[listCount];
            for (int i = 0; i < listCount; i++) {
                Super.LevelUpExperienceList[i] = Convert.ToInt32(levelList.Single(X => X.Attribute("Level").Value == i.ToString()).Attribute("Value").Value);
            }
        }

        #endregion

        #region 初始化游戏配置

        BackgroundWorker backgroundWorker;
        /// <summary>
        /// 初始化游戏配置
        /// </summary>
        private void InitializeGameConfig() {
            //设置游戏鼠标光标
            GameCursor.Stretch = Stretch.Fill;
            GameCursor.Fill = new ImageBrush() { ImageSource = Super.GetImage("/Image/Cursor/0.png") };
            //注册右键
            HtmlPage.Document.GetElementById("SilverlightHost").AttachEvent("oncontextmenu", Game_MouseRightButtonDown);
            //游戏主循环
            CompositionTarget.Rendering += new EventHandler(MainLoop);
            //设置游戏窗体辅助计时器
            DispatcherTimer auxiliaryTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(500) };
            auxiliaryTimer.Tick += new EventHandler(auxiliaryTimer_Tick);
            auxiliaryTimer.Start();
           
            //设置后台工作者
            backgroundWorker = new BackgroundWorker();
            backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
        }

        #endregion

        #region 游戏物件对象初始化

        int mapCode = 0;
        string mapData;
        #region 调试用
        int monsterCode,monsterNum, sx, sy, ex, ey;
        double leaderX = 4250, leaderY = 3400, leaderDirection = 7;
        string monsterVClan, monsterVName;
        #endregion
        /// <summary>
        /// 游戏物件对象初始化
        /// </summary>
        private void InitializeGameObject() {
            #region 调试用(实际请不要这样使用)
            switch (mapCode) {
                case 0:
                    monsterCode = 101;
                    monsterNum = 100;
                    sx = 1150; sy = 960; ex = 2600; ey = 1890;
                    monsterVClan = "[娥眉]";
                    monsterVName = "入门弟子";
                    break;
                case 1:
                    monsterCode = 100;
                    monsterNum = 30;
                    sx = 600; sy = 925; ex = 750; ey = 535;
                    monsterVClan = "[侍]";
                    monsterVName = "守剑者";
                    break;
                case 2:
                    monsterCode = 101;
                    monsterNum = 50;
                    sx = 900; sy = 760; ex = 800; ey = 400;
                    monsterVClan = "[武尊]";
                    monsterVName = "狂笑天下";
                    break;
                default:
                    monsterCode = 101;
                    monsterNum = 0;
                    sx = 50; sy = 50; ex = 400; ey = 400;
                    monsterVClan = "[无]";
                    monsterVName = "神之左手";
                    break;
            }
            #endregion
            mapData = string.Format("MapData{0}", mapCode);
            //根据地图代号获取该代号地图数据
            Super.LoadXElement(mapData, Super.GetXElement(Super.Settings["Arguments"], "Map", "Sign", mapCode.ToString()));
            //抽离地图数据中的地表层参数并用其来初始化地图地表层
            LoadMapSurface(Super.Settings[mapData].Element("Surface"));
            //抽离地图数据中的遮罩层集合并用其来初始化地图遮罩层
            LoadMapMask(Super.Settings[mapData].Element("Masks").Elements("Mask"));
            //初始化障碍物
            LoadObstruction(Super.Settings[mapData].Element("Surface"));
            //抽离传送点数据中的传送点集合并用其来初始化地图上的传送点
            LoadTeleport(Super.Settings[mapData].Element("Teleports").Elements("Teleport"));
            //加载主角
            LoadLeader(leaderX, leaderY, leaderDirection);
            //抽离精灵数据中的怪物集合并用其来初始化地图上的怪物
            LoadMonster(Super.Settings[mapData].Element("Sprites").Elements("Monster"), monsterNum, monsterCode, sx, sy, ex, ey, monsterVClan, monsterVName);
            //加载Mini地图数据
            LoadMiniMap();
            //加载游戏音乐音效
            LoadMedia();
            //加载魔法精灵
            LoadMagic();
            //加载鼠标水滴
            LoadCursor();
        }

        #endregion

        #region 初始化地图表层及地图遮罩层

        int _leaderSectionX;
        /// <summary>
        /// 主角所处的地图切片X值
        /// </summary>
        public int leaderSectionX {
            get { return _leaderSectionX; }
            set { if (_leaderSectionX != value) { _leaderSectionX = value; ChangeMapSection(); } }
        }

        int _leaderSectionY;
        /// <summary>
        /// 主角所处的地图切片Y值
        /// </summary>
        public int leaderSectionY {
            get { return _leaderSectionY; }
            set { if (_leaderSectionY != value) { _leaderSectionY = value; ChangeMapSection(); } }
        }

        int startSectionX, startSectionY, endSectionX, endSectionY, countSection;
        /// <summary>
        /// 更新呈现的地图切片(包括主地图上的和Mini地图上的)
        /// </summary>
        private void ChangeMapSection() {
            //根据主角当前位置来加载周边地图切片
            if (leaderSectionX == 0) {
                startSectionX = 0; endSectionX = 2;
            } else if (leaderSectionX == mapSectionXNum - 1) {
                startSectionX = leaderSectionX - 2; endSectionX = leaderSectionX;
            } else {
                startSectionX = leaderSectionX - 1; endSectionX = leaderSectionX + 1;
            }
            if (leaderSectionY == 0) {
                startSectionY = 0; endSectionY = 2;
            } else if (leaderSectionY == mapSectionYNum - 1) {
                startSectionY = leaderSectionY - 2; endSectionY = leaderSectionY;
            } else {
                startSectionY = leaderSectionY - 1; endSectionY = leaderSectionY + 1;
            }
            countSection = 0;
            for (int x = startSectionX; x <= endSectionX; x++) {
                for (int y = startSectionY; y <= endSectionY; y++) {
                    mapSection[countSection].Fill = new ImageBrush() { ImageSource = Super.GetImage(string.Format("/Image/Map/{0}/Surface/{1}_{2}.jpg", mapCode, x, y)) };
                    Canvas.SetLeft(mapSection[countSection], x * mapSectionWidth);
                    Canvas.SetTop(mapSection[countSection], y * mapSectionHeight);
                    countSection++;
                }
            }
        }

        Rectangle[] mapSection;
        Canvas mapSurface;
        int mapWidth, mapHeight, mapSectionWidth, mapSectionHeight, mapSectionXNum, mapSectionYNum, mapSectionNum;
        /// <summary>
        /// 初始化地图地表层
        /// </summary>
        private void LoadMapSurface(XElement args) {
            mapSurface = new Canvas() { IsHitTestVisible = false, };
            Add(mapSurface);
            mapWidth = (int)args.Attribute("Width");
            mapHeight =(int)args.Attribute("Height");
            mapSectionWidth = (int)args.Attribute("SectionWidth");
            mapSectionHeight = (int)args.Attribute("SectionHeight");
            mapSectionXNum = (int)(mapWidth / mapSectionWidth);
            mapSectionYNum = (int)(mapHeight / mapSectionHeight);
            mapSectionNum = (int)args.Attribute("SectionNum");
            mapSection = new Rectangle[mapSectionNum];
            for (int i = 0; i < mapSectionNum; i++) {
                mapSection[i] = new Rectangle() {
                    IsHitTestVisible = false,
                    Width = mapSectionWidth + 1,
                    Height = mapSectionHeight + 1,
                    Stretch = Stretch.Fill,
                };
                mapSurface.Children.Add(mapSection[i]);
            }
        }

        /// <summary>
        /// 初始化地图遮罩层
        /// </summary>
        private void LoadMapMask(IEnumerable<XElement> arglist) {
            for (int i = 0; i < arglist.Count(); i++) {
                XElement args = arglist.ElementAt(i);
                Add(new QXMap() {
                    BodySource = new ImageBrush() { ImageSource = Super.GetImage(string.Format("/Image/Map/{0}/Mask/{1}.png", mapCode, args.Attribute("Code").Value)) },
                    BodyWidth = (double)args.Attribute("BodyWidth"),
                    BodyHeight = (double)args.Attribute("BodyHeight"),
                    CenterY = (int)args.Attribute("CenterY"),
                    Coordinate = new Point((int)args.Attribute("X"), (int)args.Attribute("Y")),
                    Opacity = (double)args.Attribute("Opacity"),
                });
            }
        }

        #endregion

        #region 初始化魔法
        XElement magicData, magicValue;
        Queue<QXMagic> mlist;
        QXMagic magic; int consumption;
        private void LoadMagic() 
        {
            //加载所有魔法精灵，且每种魔法保留3份备份在缓存池当中。避免频繁new对象
            for (int j = 0; j < 6; j++)
            {
                Super.LoadXElement(string.Format("Magic{0}", j.ToString()), Super.GetXElement(Super.Settings["Arguments"], "Magic", "Code", j.ToString()));
                magicData = Super.Settings[string.Format("Magic{0}", j.ToString())];
                magicValue = Super.GetXElement(magicData, "Level", "Value", "1");
                consumption = (int)magicValue.Attribute("Consumption");
                mlist = new Queue<QXMagic>();
                for (int i = 0; i < 3; i++)
                {
                    magic = new QXMagic()
                    {

                        EndFrame = (int)magicData.Attribute("EndFrame"),
                        EffectiveFrame = (int)magicData.Attribute("EffectiveFrame"),
                        Code = j,
                        Mode = (int)magicData.Attribute("Mode"),
                        BodyWidth = (int)magicData.Attribute("BodyWidth"),
                        BodyHeight = (int)magicData.Attribute("BodyHeight"),
                        CenterX = (double)magicData.Attribute("CenterX"),
                        CenterY = (double)magicData.Attribute("CenterY"),
                        Radius = (int)magicData.Attribute("Radius"),
                        ATK = (int)magicValue.Attribute("ATK"),
                        Consumption = consumption,
                        AdditionalEffectCode = (int)magicData.Attribute("AdditionalEffectCode"),
                        AdditionalEffect = (int)magicValue.Attribute("AdditionalEffect"),
                        AdditionalEffectTime = (int)magicValue.Attribute("AdditionalEffectTime"),
                        DecorationCode = (int)magicData.Attribute("DecorationCode"),
                        DecorationWidth = (double)magicData.Attribute("DecorationWidth"),
                        DecorationHeight = (double)magicData.Attribute("DecorationHeight"),
                        DecorationEndFrame = (int)magicData.Attribute("DecorationEndFrame"),
                        DecorationType = (DecorationTypes)((int)magicData.Attribute("DecorationType")),
                    };
                    magic.Timer.Stop();
                    mlist.Enqueue(magic);
                }
                Globle.MagicList.Add(j.ToString(), mlist);
            }
        }

        #endregion

        #region 加载鼠标水滴
        private void LoadCursor() 
        { 
            Queue<QXDecoration> queue=new Queue<QXDecoration>();
             QXDecoration hitCursor;
            for(int i=0;i<5;i++)
            {
                   hitCursor = new QXDecoration() 
                 {
                    Code = 1,
                    EndFrame = 9,
                    Width = 64,
                    Height = 64,
                    CenterX = 32,
                    CenterY = 32,
                    DecorationType = DecorationTypes.AutoRemove,
                    Name="Cursor"
                   
                 };
                   hitCursor.Timer.Stop();
                   queue.Enqueue(hitCursor);
            }
            Globle.CursorList.Add("1",queue);
        }
        #endregion

        #region 初始化障碍物

        int gridSizeX, gridSizeY;
        byte[,] fixedObstruction, varyObstruction;
        /// <summary>
        /// 加载障碍物数组
        /// </summary>
        private void LoadObstruction(XElement args) {
            gridSizeX = (int)args.Attribute("GridSizeX");
            gridSizeY = (int)args.Attribute("GridSizeY");
            int size = mapWidth > mapHeight ? GetMatrixSize(mapWidth) : GetMatrixSize(mapHeight);
            fixedObstruction = new byte[size, size];
            for (int y = 0; y < fixedObstruction.GetUpperBound(1); y++) {
                for (int x = 0; x < fixedObstruction.GetUpperBound(0); x++) {
                    //设置默认值,可以通过的均在矩阵中用1表示
                    fixedObstruction[x, y] = 1;
                }
            }
            //设置初始值,可以通过的均在矩阵中用1表示
            string[]  obstruction = Super.Settings[mapData].Attribute("Obstruction").Value.Split(',');
            for (int i = 0; i < obstruction.Count(); i++) {
                string[] obstructionXY = obstruction[i].Split('_');
                fixedObstruction[Convert.ToInt32(obstructionXY[0]), Convert.ToInt32(obstructionXY[1])] = 0;
            }
            varyObstruction = fixedObstruction.Clone() as byte[,];
        }

        /// <summary>
        /// 智能获取障碍物数组尺寸
        /// </summary>
        private int GetMatrixSize(int n) {
            if (n <= 1280) {
                return 128;
            } else if (1280 < n && n <= 2560) {
                return 256;
            } else if (2560 < n && n <= 5120) {
                return 512;
            } else if (5120 < n && n <= 10240) {
                return 1024;
            } else if (10240 < n && n <= 20480) {
                return 2048;
            } else {
                return 10240;
            }
        }

        #endregion

        #region 初始化传送点

        /// <summary>
        /// 加载传送点
        /// </summary>
        private void LoadTeleport(IEnumerable<XElement> arglist) {
            for (int i = 0; i < arglist.Count(); i++) {
                XElement args = arglist.ElementAt(i);
                QXTeleport teleport = new QXTeleport() {
                    Name = string.Format("Teleport{0}", args.Attribute("Key").Value),
                    EndFrame = (int)args.Attribute("FrameNum") - 1,
                    Tip = args.Attribute("Tip").Value,
                    Code = (int)args.Attribute("Code"),
                    Key = Convert.ToByte(args.Attribute("Key").Value),
                    To = (int)args.Attribute("To"),
                    ToX = (double)args.Attribute("ToX"),
                    ToY = (double)args.Attribute("ToY"),
                    ToDirection = (double)args.Attribute("ToDirection"),
                    BodyWidth = (double)args.Attribute("BodyWidth"),
                    BodyHeight = (double)args.Attribute("BodyHeight"),
                    CenterX = (double)args.Attribute("CenterX"),
                    CenterY = (double)args.Attribute("CenterY"),
                    Coordinate = new Point((double)args.Attribute("X"), (double)args.Attribute("Y"))
                };
                Add(teleport);
                //设定传送区域
                for (int x = (int)((teleport.Coordinate.X - teleport.CenterX) / gridSizeX) + 2; x <= (int)((teleport.Coordinate.X + teleport.CenterX) / gridSizeX) - 2; x++) {
                    for (int y = (int)((teleport.Coordinate.Y - teleport.CenterY) / gridSizeY) + 2; y <= (int)((teleport.Coordinate.Y + teleport.CenterY) / gridSizeY) - 2; y++) {
                        fixedObstruction[x, y] = teleport.Key;
                    }
                }
            }
        }

        #endregion

        #region 初始化Mini地图数据

        /// <summary>
        /// 加载Mini地图图片源
        /// </summary>
        private void LoadMiniMap() {
            if (miniMap == null) { return; }
            //加载mini地图
            miniMap.MiniMap.Children.Add(new Image() {
                Name = "MiniMapImage",
                IsHitTestVisible = false,
                Stretch = Stretch.Fill,
                Source = Super.GetImage(string.Format("/Image/Map/{0}/MiniMap/0.jpg", mapCode)),
            });
            miniMap.VSName = "一区[亚特兰蒂斯]";
            miniMap.VMapName = Super.Settings[mapData].Attribute("Name").Value;
            miniMap.MapOriginalWidth = mapWidth;
            miniMap.MapOriginalHeight = mapHeight;
            miniMap.Scaling = (double)Super.Settings[mapData].Element("MiniMap").Attribute("Scaling");
            miniMap.MinScaling = (int)Super.Settings[mapData].Element("MiniMap").Attribute("MinScaling");
            miniMap.MaxScaling = (int)Super.Settings[mapData].Element("MiniMap").Attribute("MaxScaling");
        }

        #endregion

        #region 初始化主角及其他精灵对象

        QXSprite Leader;
        /// <summary>
        /// 加载主角
        /// </summary>
        private void LoadLeader(double x, double y, double direction) {
            LoadSprite(
                    ref Leader,
                    "Leader",
                    "黑木涯",
                    "[家族]一剑清心",
                    "深蓝色右手",
                    new SolidColorBrush(Colors.Orange),
                    new SolidColorBrush(Color.FromArgb(255, 96, 208, 138)),
                    new SolidColorBrush(Colors.Blue),
                    new SolidColorBrush(Color.FromArgb(255, 50, 205, 50)),
                    2500,
                    400,
                    100,
                    100,
                    1,
                    0,
                    new double[] { 50, 10, 20, 10, 10, 120, 180, 120, 100, 15, 2, 100, 10, 10, 15, 2 },
                    new double[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new double[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                    new double[] { 10, 15, 20, 4, 3, 0.2, 0.2, 0.15, 30, 10, 0.2, 10, 5, 15, 20, 0.4 },
                    160,
                    50,
                    80,
                    30,
                    60,
                    0,
                    PKModes.Whole,
                    0,
                    new int[] { 3, 6, 5, 6, 3 },
                    new int[] { -1, -1, 12, 19, 22 },
                    0,
                    0,
                    70,
                    0,
                    300,
                    new double[] { 90, 110, 75, 140 },
                    200,
                    200,
                    8,
                    23,
                    14,
                    0,
                    1,
                    100,
                    135,
                    new Point(50, 50),
                    new Point(x, y),
                    direction,
                    40
                );
            //添加新生特效
            Add(new QXDecoration() {
                Code = 2,
                EndFrame = 7,
                BodyWidth = 60,
                BodyHeight = 100,
                CenterX = 30,
                CenterY = 86,
                Coordinate = Leader.Coordinate,
                DecorationType = DecorationTypes.AutoRemove
            });
            //添加光环特效(测试用,可以作为Buff加持魔法效果)
            QXDecoration aura = new QXDecoration() {
                Code = 6,
                EndFrame = 6,
                BodyWidth = 100,
                BodyHeight = 73,
                CenterX = 50,
                CenterY = 35,
                Coordinate = new Point(100,131),
                DecorationType = DecorationTypes.Loop,
            };
            Canvas.SetZIndex(aura,-1);
            Leader.Container.Children.Add(aura);
        }

        Random random = new Random();
        QXSprite monster;
        /// <summary>
        /// 加载怪物
        /// </summary>
        private void LoadMonster(IEnumerable<XElement> arglist, int count, int monsterCode, int sx, int sy, int ex, int ey, string clan, string name) {
            for (int i = 0; i < count; i++) {
                if (FindSprite("Monster" + i.ToString()) == null) {
                    LoadSprite(
                        ref monster,
                        "Monster" + i.ToString(),
                        "莫拉克",
                        clan,
                        name,
                        null,
                        new SolidColorBrush(Color.FromArgb(255, 114, 87, 162)),
                        new SolidColorBrush(Colors.White),
                        new SolidColorBrush(Color.FromArgb(255, 226, 220, 133)),
                        6100,
                        400,
                        100,
                        100,
                        88,
                        1300,
                        new double[] { 50, 10, 20, 10, 10, 160, 180, 180, 100, 15, 2, 100, 10, 10, 15, 2 },
                        new double[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                        new double[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                        new double[] { 10, 15, 20, 4, 3, 0.2, 0.2, 0.15, 30, 10, 0.2, 10, 5, 15, 20, 0.4 },
                        45,
                        45,
                        200,
                        30,
                        5,
                        100,
                        PKModes.Whole,
                        0,
                        new int[] { 3, 6, 5, 6, 3 },
                        new int[] { -1, -1, 12, -1, 22 },
                        2,
                        2,
                        65,
                        380,
                        300,
                        new double[] { 40, 60, 25, 90 },
                        100,
                        100,
                        8,
                        23,
                        14,
                        monsterCode,
                        -1,
                        50,
                        85,
                        new Point(0, 0),
                        new Point(sx + random.Next(ex), sy + random.Next(ey)),
                        random.Next(8),
                        40
                    );
                    if (fixedObstruction[(int)(monster.Coordinate.X / gridSizeX), (int)(monster.Coordinate.Y / gridSizeY)] == 0) {
                        monster.Coordinate = new Point(sx + random.Next(ex), sy + random.Next(ey));
                    }
                }
            }
        }

        /// <summary>
        /// 加载精灵类型控件
        /// </summary>
        /// <param name="sprite">引参:对象精灵</param>
        /// <param name="name">识别名</param>
        /// <param name="faction">门派名</param>
        /// <param name="clan">家族名</param>
        /// <param name="sname">角色名</param>
        /// <param name="life">当前生命值</param>
        /// <param name="mana">当前魔法值</param>
        /// <param name="energy">当前活力值</param>
        /// <param name="energyMax">最大活力值</param>
        /// <param name="level">等级</param>
        /// <param name="experience">经验值</param>
        /// <param name="vbase">属性基数</param>
        /// <param name="equip">属性装备加成</param>
        /// <param name="buff">属性BUFF加/减持</param>
        /// <param name="coefficient">属性系数</param>
        /// <param name="power">力量</param>
        /// <param name="agile">敏捷</param>
        /// <param name="physique">体格</param>
        /// <param name="wisdom">智慧</param>
        /// <param name="lucky">幸运</param>
        /// <param name="facesign">头像</param>
        /// <param name="pkMode">PK模式</param>
        /// <param name="pkValue">PK值</param>
        /// <param name="frameRange">各动作帧数</param>
        /// <param name="effectiveFrame">各动作起效帧</param>
        /// <param name="holdWidth">占据面积宽</param>
        /// <param name="holdHeight">占据面积高</param>
        /// <param name="attackRange">物理攻击距离</param>
        /// <param name="seekRange">索敌距离</param>
        /// <param name="magicRange">施法距离</param>
        /// <param name="efficaciousSection">有效实体部分</param>
        /// <param name="singleWidth">单图宽</param>
        /// <param name="singleHeight">单图高</param>
        /// <param name="directionNum">方向数</param>
        /// <param name="bodyColFrameNum">衣服每方向帧图片数</param>
        /// <param name="WeaponColFrameNum">武器每方向帧图片数</param>
        /// <param name="equipmentBody">衣服代号</param>
        /// <param name="equipmentWeapon">武器代号</param>
        /// <param name="centerX">X中心</param>
        /// <param name="centerY">Y中心</param>
        /// <param name="componentsOffset">组件偏移量</param>
        /// <param name="coordinate">XY坐标</param>
        /// <param name="direction">朝向</param>
        /// <param name="lifeTotalWidth">头顶生命条总长度</param>
        private void LoadSprite(ref QXSprite sprite, string name, string faction, string clan, string sname, Brush factionBrush, Brush clanBrush, Brush snameBrush, Brush lifeBrush, double life, double mana, double energy, double energyMax, int level, int experience, double[] abase, double[] equip, double[] buff, double[] coefficient, int power, int agile, int physique, int wisdom, int lucky, int facesign, PKModes pkMode, int pkValue, int[] frameRange, int[] effectiveFrame, int holdWidth, int holdHeight, int attackRange, int seekRange, int magicRange, double[] efficaciousSection, int singleWidth, int singleHeight, int directionNum, int bodyColFrameNum, int WeaponColFrameNum, int equipmentBody, int equipmentWeapon, double centerX, double centerY, Point componentsOffset, Point coordinate, double direction, double lifeTotalWidth) {
            sprite = new QXSprite() {
                Name = name,
                VFaction = faction,
                VClan = clan,
                VSName = sname,
                FactionBrush = factionBrush,
                ClanBrush = clanBrush,
                SNameBrush = snameBrush,
                LifeBrush = lifeBrush,
                VLife = life,
                VMana = mana,
                VEnergy = energy,
                VEnergyMax = energyMax,
                VLevel = level,
                VExperience = experience,
                ABase = abase,
                Equip = equip,
                Buff = buff,
                Coefficient = coefficient,
                VPower = power,
                VAgile = agile,
                VPhysique = physique,
                VWisdom = wisdom,
                VLucky = lucky,
                FaceSign = facesign,
                PKMode = pkMode,
                VPK = pkValue,
                EachActionFrameRange = frameRange,
                EffectiveFrame = effectiveFrame,
                HoldWidth = holdWidth,
                HoldHeight = holdHeight,
                AttackRange = attackRange,
                SeekRange = seekRange,
                MagicRange = magicRange,
                EfficaciousSection = efficaciousSection,
                EndFrame = frameRange[0] - 1,
                SingleWidth = singleWidth,
                SingleHeight = singleHeight,
                EquipmentBody = equipmentBody,
                EquipmentWeapon = equipmentWeapon,
                CenterX = centerX,
                CenterY = centerY,
                ComponentsOffset = componentsOffset,
                Coordinate = coordinate,
                Direction = direction,
                LifeTotalWidth = lifeTotalWidth,
                Width_ = singleWidth,
                Height_ = singleHeight
            };
            //精灵头顶内容自适应窗体尺寸
            sprite.DescribtionTop = (sprite.BodyHeight - 160) / 2 - 30;
            //添加精灵
            Add(sprite);
        }

        #endregion

        #region 初始化游戏界面

        QXFacePlate leaderRoleFace, objectRoleFace;
        QXMiniMap miniMap;
        /// <summary>
        /// 初始化游戏界面
        /// </summary>
        private void InitializeGameInterface() {
            //加载主角头像面板
            leaderRoleFace = new QXFacePlate(RoleFaceTypes.Leader) {
                Left = 152,
                Top = 0,
                ZIndex = 19901,
                VSName = Leader.SName.Text,
                VLevel = Leader.VLevel.ToString(),
                FaceSign = Leader.FaceSign,
            };
            Root.Children.Add(leaderRoleFace);
            //加载监视对象头像面板
            objectRoleFace = new QXFacePlate(RoleFaceTypes.Object) {
                Left = 0,
                Top = 0,
                ZIndex = 19900,
                Visibility = Visibility.Collapsed
            };
            Root.Children.Add(objectRoleFace);
            //加载Mini地图面板
            miniMap = new QXMiniMap() {
                Name = "MiniMap",
                Left = 624,
                Top = 0,
                ZIndex = 19900,
            };
            Root.Children.Add(miniMap);
            LoadMiniMap();
        }

        /// <summary>
        /// 更新主角头像面版及相关界面显示
        /// </summary>
        private void UpdateLeaderFacePlate() {
            //更新主角生命值及显示
            leaderRoleFace.LifeWidth = leaderRoleFace.LifeTotalWidth * (Leader.VLife / Leader.VLifeMax);
            leaderRoleFace.LifeText = string.Format("{0}/{1}", Leader.VLife, Leader.VLifeMax);
            //更新主角魔法值及显示
            leaderRoleFace.MagicWidth = leaderRoleFace.MagicTotalWidth * (Leader.VMana / Leader.VManaMax);
            leaderRoleFace.MagicText = string.Format("{0}/{1}", Leader.VMana, Leader.VManaMax);
            //更新主角活力值及显示
            leaderRoleFace.EnergyWidth = leaderRoleFace.EnergyTotalWidth * (Leader.VEnergy / Leader.VEnergyMax);
            leaderRoleFace.EnergyText = string.Format("{0}/{1}", Leader.VEnergy, Leader.VEnergyMax);
            //更新主角等级
            leaderRoleFace.VLevel = Leader.VLevel.ToString();
            //更新主角经验值
            double ExperienceRate = Math.Round((double)Leader.VExperience / (double)Super.LevelUpExperienceList[Leader.VLevel + 1], 4);
            leaderRoleFace.ExperienceWidth = leaderRoleFace.ExperienceTotalWidth * ExperienceRate;
            leaderRoleFace.ExperienceText = string.Format("{0}%", ExperienceRate * 100);
            leaderRoleFace.ExperienceDetails.Text = string.Format("{0}/{1}", Leader.VExperience, Super.LevelUpExperienceList[Leader.VLevel + 1]);
            UpdateAdditionalEffectIcon(leaderRoleFace, Leader);
        }

        string watchObj = null;
        /// <summary>
        /// 更新监视对象头像面板及相关界面显示
        /// </summary>
        private void UpdateObjectFacePlate() {
            if (objectRoleFace.Visibility == Visibility.Collapsed) { return; }
            if (watchObj != null && FindSprite(watchObj) != null) {
                QXSprite obj = FindSprite(watchObj);
                objectRoleFace.VSName = obj.VSName;
                objectRoleFace.FaceSign = obj.FaceSign;
                objectRoleFace.VLevel = obj.VLevel.ToString();
                objectRoleFace.LifeWidth = objectRoleFace.LifeTotalWidth * (obj.VLife / obj.VLifeMax);
                objectRoleFace.LifeText = string.Format("{0}/{1}", obj.VLife, obj.VLifeMax);
                UpdateAdditionalEffectIcon(objectRoleFace, obj);
            }
        }

        /// <summary>
        /// //更新面板的Buff及DeBuff附加特效图标及描述
        /// </summary>
        private void UpdateAdditionalEffectIcon(QXFacePlate facePlate, QXSprite obj) {
            for (int i = 0; i < obj.AdditionalEffectTime.Count(); i++) {
                string additionalEffectName = string.Format("AdditionalEffectItem{0}", i);
                QXIcon additionalEffectIcon = facePlate.AdditionalEffectPanel.FindName(additionalEffectName) as QXIcon;
                if (obj.AdditionalEffectTime[i] > 0) {
                    XElement additionalEffectItem = Super.GetXElement(Super.Settings["AdditionalEffects"], "Item", "Value", i.ToString());
                    if (additionalEffectIcon == null) {
                        additionalEffectIcon = new QXIcon() {
                            Name = additionalEffectName,
                            Width = 16,
                            Height = 16,
                            BodySource = new ImageBrush() { ImageSource = Super.GetImage(additionalEffectItem.Attribute("Src").Value) }
                        };
                        facePlate.AdditionalEffectPanel.Children.Add(additionalEffectIcon);
                    }
                    additionalEffectIcon.Tip = string.Format("{0}持续:{1}秒", additionalEffectItem.Attribute("Name").Value, obj.AdditionalEffectTime[i]);
                } else {
                    if (additionalEffectIcon != null) {
                        facePlate.AdditionalEffectPanel.Children.Remove(additionalEffectIcon);
                        additionalEffectIcon = null;
                    }
                }
            }
        }

        #endregion

        #region 初始化游戏音乐音效

        private void LoadMedia() {
            //加载游戏音乐播放器
            Super.gameMusic = new MediaElement() {
                IsHitTestVisible = false,
                Source = new Uri(@"/Audio/music0.mp3", UriKind.Relative),
                Visibility = Visibility.Collapsed
            };
            Super.gameMusic.MediaEnded += new RoutedEventHandler(GameMusic_MediaEnded);
            Add(Super.gameMusic);
            //加载游戏音效播放器
            Super.gameAudio = new MediaElement() {
                IsHitTestVisible = false,
                Visibility = Visibility.Collapsed
            };
            Add(Super.gameAudio);
        }

        #endregion

        #region 游戏主循环

        private void MainLoop(object sender, EventArgs e) {
            //更新主角所处地图块
            leaderSectionX = (int)(Leader.Coordinate.X / mapSectionWidth);
            leaderSectionY = (int)(Leader.Coordinate.Y / mapSectionHeight);
            UpdateGameMap(MapMoving(Leader.Coordinate.X, Leader.Coordinate.Y, this.ActualWidth, this.ActualHeight, mapWidth, mapHeight));
            UpdateMiniMap(MapMoving(Leader.Coordinate.X / miniMap.Scaling, Leader.Coordinate.Y / miniMap.Scaling, miniMap.BodyMask.Width, miniMap.BodyMask.Height, mapWidth / miniMap.Scaling, mapHeight / miniMap.Scaling));
            UpdateMiniMapCoordinate();
        }

        /// <summary>
        /// 更新Mini地图面板显示主角的XY坐标
        /// </summary>
        private void UpdateMiniMapCoordinate() {
            if (miniMap.BodyVisibility == Visibility.Collapsed) { return; }
            miniMap.X = ((int)Leader.Coordinate.X).ToString();
            miniMap.Y = ((int)Leader.Coordinate.Y).ToString();
        }

        /// <summary>
        /// “托盘”主位式地图移动
        /// </summary>
        /// <param name="referenceObjX">参照物在背景地图中的X坐标</param>
        /// <param name="referenceObjY">参照物在背景地图中的Y坐标</param>
        /// <param name="containerActualWidth">呈现容器窗体的实际宽</param>
        /// <param name="containerActualHeight">呈现容器窗体的实际高</param>
        /// <param name="mapActualWidth">整张背景地图的实际宽</param>
        /// <param name="mapActualHeight">整张背景地图的实际高</param>
        /// <returns>偏移量</returns>
        private Point MapMoving(double referenceObjX, double referenceObjY, double containerActualWidth, double containerActualHeight, double mapActualWidth, double mapActualHeight) {
            if (referenceObjX <= containerActualWidth / 2 && referenceObjY <= containerActualHeight / 2) {
                //地图左上
                return new Point(0, 0);
            } else if (referenceObjX <= containerActualWidth / 2 && referenceObjY >= mapActualHeight - containerActualHeight / 2) {
                //地图左下
                return new Point(0, containerActualHeight - mapActualHeight);
            } else if (referenceObjX >= mapActualWidth - containerActualWidth / 2 && referenceObjY <= containerActualHeight / 2) {
                //地图右上
                return new Point(containerActualWidth - mapActualWidth, 0);
            } else if (referenceObjX >= mapActualWidth - containerActualWidth / 2 && referenceObjY >= mapActualHeight - containerActualHeight / 2) {
                //地图右下
                return new Point(containerActualWidth - mapActualWidth, containerActualHeight - mapActualHeight);
            } else if (referenceObjX <= containerActualWidth / 2) {
                //地图左中
                return new Point(0, containerActualHeight / 2 - referenceObjY);
            } else if (referenceObjX >= mapActualWidth - containerActualWidth / 2) {
                //地图右中
                return new Point(containerActualWidth - mapActualWidth, containerActualHeight / 2 - referenceObjY);
            } else if (referenceObjY <= containerActualHeight / 2) {
                //地图中上
                return new Point(containerActualWidth / 2 - referenceObjX, 0);
            } else if (referenceObjY >= mapActualHeight - containerActualHeight / 2) {
                //地图中下
                return new Point(containerActualWidth / 2 - referenceObjX, containerActualHeight - mapActualHeight);
            }
                //else if ((referenceObjX > containerActualWidth / 2 || referenceObjX < mapActualWidth - containerActualWidth / 2) && (referenceObjY > containerActualHeight / 2 || referenceObjY < mapActualHeight - containerActualHeight / 2)) {
                //    //地图正中
                //    return new Point(containerActualWidth / 2 - referenceObjX, containerActualHeight / 2 - referenceObjY);
                //} 
            else {
                //地图正中(或移动失败处理)
                return new Point(containerActualWidth / 2 - referenceObjX, containerActualHeight / 2 - referenceObjY);
            }
        }

        /// <summary>
        /// 刷新游戏地图中的地图图片位置
        /// </summary>
        /// <param name="offset">偏移量</param>
        private void UpdateGameMap(Point offset) {
            if (Canvas.GetLeft(Carrier) != offset.X) { Canvas.SetLeft(Carrier, offset.X); }
            if (Canvas.GetTop(Carrier) != offset.Y) { Canvas.SetTop(Carrier, offset.Y); }
            for (int i = 0; i < Carrier.Children.Count; i++) {
                if (Carrier.Children[i] is QXSprite) {
                    QXSprite sprite = Carrier.Children[i] as QXSprite;
                    if (sprite.Visibility == Visibility.Visible) {
                        ActiveSprite(sprite);
                    }
                }
            }
        }

        /// <summary>
        /// 更新mini地图中地图图片位置
        /// </summary>
        /// <param name="offset">偏移量</param>
        private void UpdateMiniMap(Point offset) {
            if (miniMap.BodyVisibility == Visibility.Collapsed) { return; }
            if (Canvas.GetLeft(miniMap.MiniMap) != offset.X) { Canvas.SetLeft(miniMap.MiniMap, offset.X); }
            if (Canvas.GetTop(miniMap.MiniMap) != offset.Y) { Canvas.SetTop(miniMap.MiniMap, offset.Y); }
        }

        /// <summary>
        /// 游戏中的所有对象物体激发相应动作
        /// </summary>
        private void ActiveSprite(QXSprite sprite) {
            if (sprite.LockObject == null) {
                if (sprite.Action == Actions.Run && WillCollide(sprite,sprite.Destination)) {
                    AStarMove(sprite, sprite.Destination);
                }
            } else {
                QXSprite enemy = FindSprite(sprite.LockObject);
                if (enemy.VLife == 0) {
                    sprite.LockObject = null;
                    if (sprite.Action != Actions.Magic) { 
                        sprite.Action = Actions.Stop; 
                        Super.RemoveStoryboard(sprite.Name); 
                    }
                } else {
                    if (sprite.Action != Actions.Attack && WillAttack(sprite, FindSprite(sprite.LockObject))) {
                        sprite.Action = Actions.Attack;
                        Super.RemoveStoryboard(sprite.Name);
                    } else if (sprite.Action == Actions.Run && WillCollide(sprite, sprite.Destination)) {
                        if (sprite == Leader) {
                            AStarMove(sprite, GetSpriteEdge(enemy));
                        } else {
                            if (!sprite.UseAStarMove) {
                                SetSpriteObstruction(sprite, 1);
                                AStarMove(sprite, GetSpriteEdge(enemy));
                                sprite.UseAStarMove = true;
                                SetSpriteObstruction(sprite, 0);
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 设置精灵占位障碍物对应值
        /// </summary>
        private void SetSpriteObstruction(QXSprite sprite, byte sign) {
            int x = (int)(sprite.Coordinate.X / gridSizeX);
            int y = (int)(sprite.Coordinate.Y / gridSizeY);
            for (int m = x - sprite.HoldWidth; m <= x + sprite.HoldWidth; m++) {
                for (int n = y - sprite.HoldHeight; n <= y + sprite.HoldHeight; n++) {
                    if (fixedObstruction[m, n] != 0) {
                        varyObstruction[m, n] = sign;
                    }
                }
            }
        }

        /// <summary>
        /// 获取精灵边缘
        /// </summary>
        private Point GetSpriteEdge(QXSprite sprite) {
            return new Point(sprite.Coordinate.X + random.Next(-(sprite.HoldWidth + 1), (sprite.HoldWidth + 1)) * gridSizeX, sprite.Coordinate.Y + random.Next(-(sprite.HoldHeight + 1), (sprite.HoldHeight + 1)) * gridSizeY);
        }

        /// <summary>
        /// 判断是否将要碰撞到障碍物(障碍物预测法)
        /// </summary>
        private bool WillCollide(QXSprite sprite, Point p) {
            return WillCollide(sprite, (int)Super.GetDirectionByTan(p.X, p.Y, sprite.Coordinate.X, sprite.Coordinate.Y));
        }

        /// <summary>
        /// 判断是否将要碰撞到障碍物(障碍物预测法)
        /// </summary>
        private bool WillCollide(QXSprite sprite, int direction) {
            switch (direction) {
                case 0:
                    return varyObstruction[(int)(sprite.Coordinate.X / gridSizeX), (int)(sprite.Coordinate.Y / gridSizeY) - sprite.HoldHeight - 1] == 0 ? true : false;
                case 1:
                    return varyObstruction[(int)(sprite.Coordinate.X / gridSizeX) + sprite.HoldWidth + 1, (int)(sprite.Coordinate.Y / gridSizeY) - sprite.HoldHeight - 1] == 0 ? true : false;
                case 2:
                    return varyObstruction[(int)(sprite.Coordinate.X / gridSizeX) + sprite.HoldWidth + 1, (int)(sprite.Coordinate.Y / gridSizeY)] == 0 ? true : false;
                case 3:
                    return varyObstruction[(int)(sprite.Coordinate.X / gridSizeX) + sprite.HoldWidth + 1, (int)(sprite.Coordinate.Y / gridSizeY) + sprite.HoldHeight + 1] == 0 ? true : false;
                case 4:
                    return varyObstruction[(int)(sprite.Coordinate.X / gridSizeX), (int)(sprite.Coordinate.Y / gridSizeY) + sprite.HoldHeight + 1] == 0 ? true : false;
                case 5:
                    return varyObstruction[(int)(sprite.Coordinate.X / gridSizeX) - sprite.HoldWidth - 1, (int)(sprite.Coordinate.Y / gridSizeY) + sprite.HoldHeight + 1] == 0 ? true : false;
                case 6:
                    return varyObstruction[(int)(sprite.Coordinate.X / gridSizeX) - sprite.HoldWidth - 1, (int)(sprite.Coordinate.Y / gridSizeY)] == 0 ? true : false;
                case 7:
                    return varyObstruction[(int)(sprite.Coordinate.X / gridSizeX) - sprite.HoldWidth - 1, (int)(sprite.Coordinate.Y / gridSizeY) - sprite.HoldHeight - 1] == 0 ? true : false;
                default:
                    return true;
            }
        }

        /// <summary>
        /// 判断是否将要向锁定对象发起攻击
        /// </summary>
        private bool WillAttack(QXSprite attacker, QXSprite defenser) {
            return defenser == null ? false : Super.InCircle(attacker.Coordinate, defenser.Coordinate, attacker.AttackRange);
        }

        #endregion

        #region 游戏后台计时器间隔事件

        //辅助线程间隔事件
        private void auxiliaryTimer_Tick(object sender, EventArgs e) {
            if (!backgroundWorker.IsBusy) { backgroundWorker.RunWorkerAsync(); }
            //同步激发精灵附加属性效果
            for (int i = 0; i < Carrier.Children.Count; i++) {
                if (Carrier.Children[i] is QXSprite) {
                    QXSprite sprite = Carrier.Children[i] as QXSprite;
                    if (sprite.VLife > 0) {
                        for (int j = 0; j < sprite.AdditionalEffectTime.Count(); j++) {
                            if (sprite.AdditionalEffectTime[j] > 0) {
                                //中毒则每秒伤血
                                if (j == 3) {
                                    Super.DoInjure(FindSprite(sprite.AdditionalEffectSprite), sprite, sprite.AdditionalEffect[j]);
                                }
                                //持续时间减少
                                sprite.AdditionalEffectTime[j] = sprite.AdditionalEffectTime[j] - 0.5;
                                if (sprite.AdditionalEffectTime[j] <= 0) {
                                    //移除附加效果
                                    Super.RemoveAdditionalEffect(sprite, j);
                                }
                            }
                        }
                    }
                }
            }
        }
        //接受数据包进行处理
        private void gamePacketTimer_Tick(object sender, EventArgs e) 
        { 

        }
        //后台数据处理工作事件
        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) {
            this.Dispatcher.BeginInvoke(() => {
                //更新界面元素
                UpdateLeaderFacePlate();
                UpdateObjectFacePlate();
                UpdateOthers();
            });
        }

        /// <summary>
        /// 刷新动态障碍物数组及追踪对象
        /// </summary>
        private void UpdateOthers() {
            //判断主角是否在传送点
            int leaderNowX = (int)(Leader.Coordinate.X / gridSizeX);
            int leaderNowY = (int)(Leader.Coordinate.Y / gridSizeY);
            if (fixedObstruction[leaderNowX, leaderNowY] >= 10) {
                MapConversion(fixedObstruction[leaderNowX, leaderNowY]);
            }
            //将当前动态障碍物重置为原始固定值
            varyObstruction = fixedObstruction.Clone() as byte[,];
            //重新填充动态障碍物
            for (int i = 0; i < Carrier.Children.Count; i++) {
                if (Carrier.Children[i] is QXSprite) {
                    QXSprite sprite = Carrier.Children[i] as QXSprite;
                    //隐藏或显示mini地图区域范围内精灵
                    if (miniMap.BodyVisibility == Visibility.Visible) {
                        //这个12和10是这样算出来的，mini地图宽约是实际地图的1/6，而高则是实际地图的1/5，大家要根据自己的Mini地图呈现窗口尺寸来设定搜索目标范围
                        UIElement uie = miniMap.MiniMap.FindName(string.Format("Obj{0}", sprite.Name)) as UIElement;
                        if ((Math.Abs(sprite.Coordinate.X - Leader.Coordinate.X) > this.ActualWidth / 12 * miniMap.Scaling) || (Math.Abs(sprite.Coordinate.Y - Leader.Coordinate.Y) > this.ActualHeight / 10 * miniMap.Scaling)) {
                            if (uie != null) {
                                Remove(miniMap.MiniMap, uie);
                            }
                        } else {
                            if (uie == null) {
                                if (sprite == Leader) {
                                    miniMap.MiniMap.Children.Add(new TextBlock() {
                                        Name = string.Format("Obj{0}", sprite.Name),
                                        Text = Leader.VSName,
                                        FontSize = 10,
                                        Foreground = new SolidColorBrush(Color.FromArgb(255, 206, 241, 190)),
                                    });
                                } else {
                                    miniMap.MiniMap.Children.Add(new Rectangle() {
                                        Name = string.Format("Obj{0}", sprite.Name),
                                        Width = 6,
                                        Height = 6,
                                        RadiusX = 3,
                                        RadiusY = 3,
                                        Stretch = Stretch.Fill,
                                        Fill = new SolidColorBrush(Color.FromArgb(255, 184, 105, 167)),
                                        StrokeThickness = 1,
                                        Stroke = new SolidColorBrush(Color.FromArgb(255, 88, 88, 88))
                                    });
                                }
                            } else {
                                double left = sprite.Coordinate.X / miniMap.Scaling, top = sprite.Coordinate.Y / miniMap.Scaling;
                                if (Canvas.GetLeft(uie) != left) { Canvas.SetLeft(uie, left - ((double)uie.GetValue(ActualWidthProperty) / 2)); }
                                if (Canvas.GetTop(uie) != top) { Canvas.SetTop(uie, top - ((double)uie.GetValue(ActualHeightProperty) / 2)); }
                            }
                        }
                    }
                    //调试用
                    //Leader.VFaction = miniMap.MiniMap.Children.Count.ToString();
                    //隐藏或显示区域范围内精灵
                    if ((Math.Abs(sprite.Coordinate.X - Leader.Coordinate.X) > this.ActualWidth / 2) || (Math.Abs(sprite.Coordinate.Y - Leader.Coordinate.Y) > this.ActualHeight / 2)) {
                        sprite.Visibility = Visibility.Collapsed;
                        sprite.Timer.Stop();
                    } else {
                        if (!sprite.Timer.IsEnabled) {
                            sprite.Visibility = Visibility.Visible;
                            sprite.Timer.Start();
                        }
                        //精灵头顶血条
                        sprite.LifeWidth = sprite.LifeTotalWidth * (sprite.VLife / sprite.VLifeMax);
                        //有攻击对象且没被冰冻
                        if (sprite.LockObject != null && sprite.AdditionalEffectTime[2] <= 0) {
                            QXSprite obj = FindSprite(sprite.LockObject);
                            //一旦攻击对象逃跑(不在自己的攻击距离内)则追踪
                            if (!WillAttack(sprite, obj)) {
                                LinearMove(sprite, GetSpriteEdge(obj));
                            } else {
                                ChangeDirection(sprite, obj.Coordinate);
                            }
                        }
                        //将所有非自己的精灵占据区域更新视为障碍物
                        if (sprite != Leader) {
                            sprite.UseAStarMove = false;
                            SetSpriteObstruction(sprite, 0);
                            //非主角精灵索敌(进入攻击视线内)
                            if (sprite.VLife != 0 && Super.InCircle(Leader.Coordinate, sprite.Coordinate, sprite.SeekRange) && Super.IsOpposition(sprite, Leader)) {
                                sprite.LockObject = Leader.Name;
                            } else {
                                sprite.LockObject = null;
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 地图切换
        /// </summary>
        /// <param name="teleportCode">传送点索引</param>
        private void MapConversion(int teleportCode) {
            //取得踩中的传送点对象
            QXTeleport teleport = FindName(string.Format("Teleport{0}", teleportCode)) as QXTeleport;
            mapCode = teleport.To; leaderX = teleport.ToX; leaderY = teleport.ToY; leaderDirection = teleport.ToDirection;
            //清空移动动画板
            foreach (Storyboard sb in Super.storyboard.Values) {
                sb.Stop(); 
                sb.Completed -= Move_Completed;
            }
            Super.storyboard.Clear();
            //清空并暂停所有对象
            for (int i = 0; i < Carrier.Children.Count; i++) {
                if (Carrier.Children[i] is IObject) {
                    Super.RemoveObject(Carrier.Children[i] as IObject, false);
                }
            }
            mapSurface.Children.Clear();
            Carrier.Children.Clear();
            //清空mini地图中的对象
            miniMap.MiniMap.Children.Clear();
            //重新初始化游戏物件对象(包括主角)
            //意味着所有怪物回归原点(如果想保留怪物后来坐标,可以通过xml等来保存
            //如果是网络游戏则简单多了,只需同步读取新地图怪物的数据就可以了
            InitializeGameObject();
            ChangeMapSection();
        }

        #endregion

        #region 鼠标左键事件及移动相关方法

        //鼠标左键事件
        private void Game_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
            if (Leader.VLife == 0) { return; }
            watchObj = null;
            Leader.IsMagicMove = false;
            Point p = e.GetPosition(Root);
            if (HitSprite(p) != null) {
                hitSprite = HitSprite(p);
                for (int i = 0; i < hitSprite.Count; i++) {
                    if (IsEfficaciousSection(hitSprite[i].EfficaciousSection, e.GetPosition(hitSprite[i]))) {
                        watchObj = hitSprite[i].Name;
                        break;
                    }
                }
            }
            //假如点到了目标对象，则进行相关判断
            if (watchObj != null) {
                QXSprite enemy = FindSprite(watchObj);
                //主动更新监视对象头像面板
                objectRoleFace.Visibility = Visibility.Visible;
                UpdateObjectFacePlate();
                //假如是敌对的且还没死
                if (Super.IsOpposition(Leader, enemy) && enemy.VLife != 0) {
                    //锁定攻击目标
                    Leader.LockObject = watchObj;
                    if (!WillAttack(Leader, enemy)) {
                        LinearMove(Leader, enemy.Coordinate);
                    } else {
                        ChangeDirection(Leader, enemy.Coordinate);
                    }
                }
            } else {
                p = e.GetPosition(mapSurface);
                //出现光标水滴
                QXDecoration hitCursor = Super.GetCursorByCode(1);
                Add(hitCursor);
                hitCursor.Coordinate = p;
                //取消锁定
                Leader.LockObject = null;
                objectRoleFace.Visibility = Visibility.Collapsed;
                //点到的地方不是障碍物才能移动
                if (varyObstruction[(int)(p.X / gridSizeX), (int)(p.Y / gridSizeY)] != 0) {
                    LinearMove(Leader, p);
                }
            }
        }

        /// <summary>
        /// 直线移动
        /// </summary>
        private void LinearMove(QXSprite sprite, Point p) {
            //假如冰冻,则不能移动
            if (sprite.AdditionalEffectTime[2] > 0) { return; }
            //假如混乱则乱动
            if (sprite.AdditionalEffectTime[1] > 0) { p = new Point(p.X + (p.X > sprite.Coordinate.X ? -random.Next(200) : random.Next(200)), p.Y + (p.Y > sprite.Coordinate.Y ? -random.Next(200) : random.Next(200))); }
            Super.NewStoryboard(sprite.Name);
            Super.storyboard[sprite.Name].Completed += new EventHandler(Move_Completed);
            //计算总的移动花费
            double moveCost = Math.Sqrt(Math.Pow((p.X - sprite.Coordinate.X) / gridSizeX, 2) + Math.Pow((p.Y - sprite.Coordinate.Y) / gridSizeY, 2)) * sprite.VRunSpeed * 0.9;
            //改变朝向
            double newDirection = Super.GetDirectionByTan(p.X, p.Y, sprite.Coordinate.X, sprite.Coordinate.Y);
            DoubleAnimation doubleAnimation = new DoubleAnimation() {
                To = newDirection,
                Duration = new Duration(TimeSpan.Zero)
            };
            Storyboard.SetTarget(doubleAnimation, sprite);
            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Direction"));
            Super.storyboard[sprite.Name].Children.Add(doubleAnimation);
            sprite.Destination = p;
            if (WillCollide(sprite, (int)newDirection)) {
                AStarMove(sprite, p);
            } else {
                //创建坐标变换属性动画
                PointAnimation pointAnimation = new PointAnimation() {
                    To = p,
                    Duration = new Duration(TimeSpan.FromMilliseconds(moveCost))
                };
                Storyboard.SetTarget(pointAnimation, sprite);
                Storyboard.SetTargetProperty(pointAnimation, new PropertyPath("Coordinate"));
                Super.storyboard[sprite.Name].Children.Add(pointAnimation);
                //启动属性动画
                sprite.Action = Actions.Run;
                Super.storyboard[sprite.Name].Begin();
            }
        }

        /// <summary>
        /// A*寻路移动
        /// </summary>
        private void AStarMove(QXSprite sprite, Point p) {
            //假如冰冻,则不能移动
            if (sprite.AdditionalEffectTime[2] > 0) { return; }
            //假如混乱则停A*
            if (sprite.AdditionalEffectTime[1] > 0) { p = sprite.Coordinate; }
            //进行单元格缩小
            Point start = new Point() {
                X = sprite.Coordinate.X / gridSizeX,
                Y = sprite.Coordinate.Y / gridSizeY
            },
            end = new Point() {
                X = p.X / gridSizeX,
                Y = p.Y / gridSizeY
            };
            if (start != end) {
                PathFinderFast pathFinderFast = new PathFinderFast(varyObstruction) {
                    HeavyDiagonals = false,
                    HeuristicEstimate = 100,
                };
                List<PathFinderNode> path = pathFinderFast.FindPath(start, end);
                if (path == null || path.Count <= 1) {
                    //路径不存在
                    sprite.Action = Actions.Stop;
                    Super.RemoveStoryboard(sprite.Name);
                } else {
                    Super.NewStoryboard(sprite.Name);
                    Super.storyboard[sprite.Name].Completed += new EventHandler(Move_Completed);
                    //创建朝向动画
                    DoubleAnimationUsingKeyFrames doubleAnimationUsingKeyFrames = new DoubleAnimationUsingKeyFrames() {
                        Duration = new Duration(TimeSpan.FromMilliseconds(path.Count * sprite.VRunSpeed)) //总共花费时间
                    };
                    Storyboard.SetTarget(doubleAnimationUsingKeyFrames, sprite);
                    Storyboard.SetTargetProperty(doubleAnimationUsingKeyFrames, new PropertyPath("Direction"));
                    //创建坐标变换逐帧动画
                    PointAnimationUsingKeyFrames pointAnimationUsingKeyFrames = new PointAnimationUsingKeyFrames() {
                        Duration = new Duration(TimeSpan.FromMilliseconds(path.Count * sprite.VRunSpeed))
                    };
                    Storyboard.SetTarget(pointAnimationUsingKeyFrames, sprite);
                    Storyboard.SetTargetProperty(pointAnimationUsingKeyFrames, new PropertyPath("Coordinate"));
                    LinearPointKeyFrame linearPointKeyFrame; LinearDoubleKeyFrame LinearDoubleKeyFrame;
                    for (int i = path.Count - 1; i >= 0; i--) {
                        //加入坐标变换的匀速关键帧
                        linearPointKeyFrame = new LinearPointKeyFrame() {
                            KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(sprite.VRunSpeed * (path.Count - 1 - i)))
                        };
                        //平滑衔接动画(将寻路坐标系中的坐标放大回地图坐标系中的坐标)
                        if (i == path.Count - 1) {
                            linearPointKeyFrame.Value = sprite.Coordinate;
                        } else if (i == 0) {
                            linearPointKeyFrame.Value = sprite.Destination;
                        } else {
                            linearPointKeyFrame.Value = new Point(path[i].X * gridSizeX + gridSizeX / 2, path[i].Y * gridSizeY + gridSizeY / 2); //+ GridSize / 2为偏移处理
                        }
                        pointAnimationUsingKeyFrames.KeyFrames.Add(linearPointKeyFrame);
                        //加入朝向匀速关键帧
                        LinearDoubleKeyFrame = new LinearDoubleKeyFrame() {
                            KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(sprite.VRunSpeed * (path.Count - 1 - i)))
                        };
                        LinearDoubleKeyFrame.Value = i == 0
                            ? Super.GetDirectionByAspect((int)path[i].X, (int)path[i].Y, (int)path[i + 1].X, (int)path[i + 1].Y)
                            : Super.GetDirectionByAspect((int)path[i - 1].X, (int)path[i - 1].Y, (int)path[i].X, (int)path[i].Y)
                        ;
                        doubleAnimationUsingKeyFrames.KeyFrames.Add(LinearDoubleKeyFrame);
                    }
                    Super.storyboard[sprite.Name].Children.Add(pointAnimationUsingKeyFrames);
                    Super.storyboard[sprite.Name].Children.Add(doubleAnimationUsingKeyFrames);
                    //启动属性动画
                    Super.storyboard[sprite.Name].Begin();
                    sprite.Action = Actions.Run;
                }
            }
        }

        /// <summary>
        /// 移动结束
        /// </summary>
        private void Move_Completed(object sender, EventArgs e) {
            //此处需要更好的处理方案,如果不用Storyboard移动,则方便很多
            try {
                QXSprite sprite = FindSprite(Super.storyboard.Single(X => X.Value == sender as Storyboard).Key);
                if (sprite.IsMagicMove) {
                    SpellCasting(sprite);
                } else {
                    if (sprite.Action != Actions.Magic) {
                        sprite.Action = Actions.Stop;
                        Super.RemoveStoryboard(sprite.Name);
                    }
                }
            } catch { return; }
        }

        #endregion

        #region 鼠标右键事件

        //鼠标右键事件
        private void Game_MouseRightButtonDown(object sender, HtmlEventArgs e) {
            e.PreventDefault(); //取消右键弹出菜单
            if (Leader.VLife == 0) { return; }
            Leader.LockObject = null;
            Point p = new Point(e.OffsetX - (double)Carrier.GetValue(Canvas.LeftProperty), e.OffsetY - (double)Carrier.GetValue(Canvas.TopProperty));
            Leader.MagicTarget = p;
            //假如点击的地方太远则先跑到施法范围再施法,否则直接施法
            if (Super.InCircle(Leader.Coordinate, p, Leader.MagicRange)) {
                SpellCasting(Leader);
            } else {
                Leader.IsMagicMove = true;
                double n = Math.Sqrt(Math.Pow(p.Y - Leader.Coordinate.Y, 2) + Math.Pow(p.X - Leader.Coordinate.X, 2));
                double x = p.X - (p.X - Leader.Coordinate.X) * Leader.MagicRange / n;
                double y = p.Y - (p.Y - Leader.Coordinate.Y) * Leader.MagicRange / n;
                //设置精灵的最终移动目的地
                LinearMove(Leader, new Point(x, y));
            }
        }

        /// <summary>
        /// 施法
        /// </summary>
        private void SpellCasting(QXSprite magicer) {
            Super.RemoveStoryboard(magicer.Name);
            magicer.MagicArgs = new int[] { Convert.ToInt32(((ComboBoxItem)MagicSelector.SelectedItem).Tag.ToString()), Convert.ToInt32(((ComboBoxItem)MagicLevelSelector.SelectedItem).Content.ToString()) };
            ChangeDirection(magicer, magicer.MagicTarget);
            magicer.Action = Actions.Magic;
        }

        #endregion

        #region 鼠标悬停事件及命中测试方法

        //鼠标移动(悬停)事件
        private void Game_MouseMove(object sender, MouseEventArgs e) {
            this.Dispatcher.BeginInvoke(() => {
                Point p = e.GetPosition(Root);
                GameCursor.SetValue(Canvas.LeftProperty, p.X); GameCursor.SetValue(Canvas.TopProperty, p.Y);
                //去掉之前所有可能的精灵外发光
                if (hitSprite.Count > 0) {
                    for (int i = 0; i < hitSprite.Count; i++) {
                        hitSprite[i].ShadowVisible = false;
                    }
                }
                //拾取被鼠标选中的精灵
                if (HitSprite(p) != null) {
                    hitSprite = HitSprite(p);
                    bool targetIsFound = false;
                    for (int i = 0; i < hitSprite.Count; i++) {
                        if (!targetIsFound && IsEfficaciousSection(hitSprite[i].EfficaciousSection, e.GetPosition(hitSprite[i]))) {
                            GameCursor.Fill = new ImageBrush() { ImageSource = Super.IsOpposition(Leader, hitSprite[i]) ? GetCursor(1) : GetCursor(2) };
                            hitSprite[i].ShadowVisible = true;
                            targetIsFound = true;
                        }
                    }
                    if (!targetIsFound) {
                        GameCursor.Fill = new ImageBrush() { ImageSource = GetCursor(0) };
                    }
                }
            });
        }

        List<QXSprite> hitSprite = new List<QXSprite>();
        /// <summary>
        /// 命中测试
        /// </summary>
        private List<QXSprite> HitSprite(Point p) {
            hitSprite.Clear();
            List<UIElement> hitElements = VisualTreeHelper.FindElementsInHostCoordinates(p, Carrier) as List<UIElement>;
            //根据实际情况调试这个小于的数字,检测方法为鼠标悬停在主角上时有反应
            if (hitElements.Count < 4) {
                return null;
            } else {
                //从2开始,因为还有两个对象在最早被发现
                for (int i = 2; i < hitElements.Count; i++) {
                    if (hitElements[i] is QXSprite) {
                        QXSprite sprite = hitElements[i] as QXSprite;
                        hitSprite.Add(sprite);
                    }
                }
                return hitSprite.Count > 0 ? hitSprite : null;
            }
        }

        /// <summary>
        /// 判断点是否在精灵实体有效区域
        /// </summary>
        private bool IsEfficaciousSection(double[] efficaciousSection, Point p) {
            return p.X >= efficaciousSection[0] && p.X <= efficaciousSection[1] && p.Y >= efficaciousSection[2] && p.Y <= efficaciousSection[3] ? true : false;
        }

        #endregion

        #region 其他方法

        /// <summary>
        /// 获取画布Name精灵控件
        /// </summary>
        private QXSprite FindSprite(string name) {
            return Carrier.FindName(name) as QXSprite;
        }

        /// <summary>
        /// 添加控件进画布
        /// </summary>
        private void Add(UIElement u) {
            Carrier.Children.Add(u);
        }

        /// <summary>
        /// 移除画布中控件
        /// </summary>
        private void Remove(Canvas container, UIElement uie) {
            container.Children.Remove(uie);
            uie = null;
        }

        /// <summary>
        /// 获取鼠标指针
        /// </summary>
        private ImageSource GetCursor(int code) {
            return Super.GetImage(string.Format("/Image/Cursor/{0}.png", code));
        }

        /// <summary>
        /// 改变精灵的朝向
        /// </summary>
        private void ChangeDirection(QXSprite sprite, Point p) {
            double direction = Super.GetDirectionByTan(p.X, p.Y, sprite.Coordinate.X, sprite.Coordinate.Y);
            if (sprite.Direction != direction) {
                Super.NewStoryboard(sprite.Name);
                DoubleAnimation doubleAnimation = new DoubleAnimation() {
                    To = direction,
                    Duration = new Duration(TimeSpan.Zero)
                };
                Storyboard.SetTarget(doubleAnimation, sprite);
                Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Direction"));
                Super.storyboard[sprite.Name].Children.Add(doubleAnimation);
                Super.storyboard[sprite.Name].Begin();
            }
        }

        //音乐循环事件
        private void GameMusic_MediaEnded(object sender, EventArgs e) {
            Super.gameMusic.Stop();
            Super.gameMusic.Play();
        }

        //换衣服
        private void BodySelector_SelectionChanged(object sender, SelectionChangedEventArgs e) {
            if (Leader != null) {
                Leader.EquipmentBody = Convert.ToInt32(((ComboBoxItem)BodySelector.SelectedItem).Tag.ToString());
            }
        }

        //换武器
        private void WeaponSelector_SelectionChanged(object sender, SelectionChangedEventArgs e) {
            if (Leader != null) {
                int EquipmentWeaponNum = Convert.ToInt32(((ComboBoxItem)WeaponSelector.SelectedItem).Tag.ToString());
                if (EquipmentWeaponNum == -1) { Leader.Body.Stretch = Stretch.None; } else { Leader.Body.Stretch = Stretch.Fill; }
                Leader.EquipmentWeapon = EquipmentWeaponNum;
            }
        }

        //音乐开关
        private void MusicSelector_SelectionChanged(object sender, SelectionChangedEventArgs e) {
            if (MusicSelector != null) {
                if (((ComboBoxItem)MusicSelector.SelectedItem).Content.ToString() == "开") {
                    Super.gameMusic.IsMuted = false;
                    Super.gameAudio.IsMuted = false;
                } else {
                    Super.gameMusic.IsMuted = true;
                    Super.gameAudio.IsMuted = true;
                }
            }
        }

        //刷怪
        private void Button_Click_1(object sender, RoutedEventArgs e) {
            LoadMonster(Super.Settings[mapData].Element("Sprites").Elements("Monster"),Convert.ToInt32(textbox1.Text), monsterCode, sx, sy, ex, ey, monsterVClan, monsterVName);
            GC.Collect();
        }

        //满血满魔(复活)
        private void Button_Click_2(object sender, RoutedEventArgs e) {
            if (FindSprite("Leader") == null) {
                LoadLeader(leaderX, leaderY, leaderDirection);
            } else {
                if (Leader.Action == Actions.Death) {
                    Leader.Action = Actions.Stop;
                }
                Leader.VLife = Leader.VLifeMax;
                Leader.VMana = Leader.VManaMax;
            }
        }

        #endregion

    }
}
